package app

import (
	"github.com/gorilla/websocket"
	"net/http"
	"os"
	"reflect"
	"strings"
)

type Server struct {
	ConfigFile string           //
	Config     TomlFileCFG      //
	waitGroup  WaitGroupWrapper //
}

var (
	//server
	ser Server

	// ws 的所有连接 用于广播
	wsConnAll = make(map[int64]*wsConnection)

	// 最大的连接ID，每次连接都加1 处理
	maxConnId int64 = 0
)

func (ser *Server) Run() error {

	ser.waitGroup.Wrap(func() {
		err := http.ListenAndServe(ser.Config.Http.ListenIp+":"+ser.Config.Http.ListenPort, ser)
		if err != nil {
			P("run http server error ", err.Error())
		}
	})

	ser.waitGroup.Wait()
	return nil
}

/**
http-api-server
*/
func (ser *Server) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	ctx := NewContext(res, req, ser)
	defer func() { ctx = nil }()
	clientIp := ClientIP(req)

	//配置白名单
	if len(ser.Config.System.WhiteIP) > 0 &&
		InStringArray(clientIp, ser.Config.System.WhiteIP) == false {
		P("IP[" + clientIp + "] not allowed access")
		ctx.ShowHtml(403, "IP禁止访问")
		return
	}

	var err error

	/**
	处理websocket请求
	*/
	if websocket.IsWebSocketUpgrade(req) {
		err = wsHandler(res, req)
		if err != nil {
			P("[ws][wsHandler][" + err.Error() + "]")
			return
		}

		return
	}

	//首页
	if req.URL.String() == "/" {
		(&ApiController{}).Index(ctx)
		return
	}

	//处理资源处理
	filePath := "static" + strings.ReplaceAll(req.URL.Path, "/", string(os.PathSeparator))
	f, err := os.Stat(filePath)
	if err == nil && f != nil {
		if f.IsDir() == true {
			filePath += string(os.PathSeparator) + "index.html"
		}
		http.ServeFile(res, req, filePath)
		return
	}

	//处理http请求 路由策略
	val := reflect.ValueOf(&ApiController{}).MethodByName(ctx.FuncName)
	if val.IsValid() {
		P("[api][" + ctx.FuncName + "]")
		params := make([]reflect.Value, 0)
		params = append(params, reflect.ValueOf(ctx))
		val.Call(params)
	} else {
		P("[api][PageNotFound][" + req.URL.String() + "]")
		ctx.ShowHtml(404, "页面未找到")
	}
}

/**
实例化
*/
func NewServer() *Server {
	ser.ConfigFile = "config" + string(os.PathSeparator) + "config.toml"
	ser.LoadConfig() //加载配置
	return &ser
}
